use std::io::Error;
use serde::{Serialize, Deserialize};
use std::fs::File;
use std::io::BufReader;
use tracing::error;


#[derive(Debug, Clone, Serialize,Deserialize)]
pub struct AppConfig{  
   pub server: Vec<ServerConfig>,
   pub logger:LogConfig,
   pub timeout: Option<u16>,
   pub retry_interval: Option<u16>,
   pub retry_times: Option<u16>,
}

impl Default for AppConfig {
    fn default() -> Self {
        let server = ServerConfig::default();
        AppConfig{
            server:vec![server],
            logger:LogConfig::default(),
            timeout: Some(60),
            retry_interval: Some(10),
            retry_times:Some(3),
        }
    }
}

#[derive(Debug, Clone, Serialize,Deserialize)]
pub enum LogLevel {
    None,
    Trace,
    Debug,
    Info,
    Warn,
    Error,
    Final,
}


#[derive(Debug, Clone, Serialize,Deserialize)]
pub enum RollType {
    Single,
    Daily,
}


#[derive(Debug, Clone, Serialize,Deserialize)]
pub struct LogConfig{
    pub out_dir:String,
    pub file_prefix: String,
    pub roll:RollType,
    pub level: LogLevel,
    pub output_cli:bool,
}

impl Default for LogConfig {
    fn default() -> Self {
        LogConfig{
            out_dir:"log".to_owned(),
            file_prefix:"app".to_owned(),
            roll: RollType::Daily,
            level:LogLevel::Info,
            output_cli: true,
        }
    }
}

#[derive(Debug, Clone, Serialize,Deserialize)]
pub struct ServerConfig{
    pub host:String,
    pub username: String,
    pub password:String,
    pub virtual_host: String,
    pub port:u16,
    pub heartbeat:u32,
    pub queue_list: Vec<ServerQueueConfig>,
}


impl Default for ServerConfig {
    fn default() -> Self {
        ServerConfig{
            host:"127.0.0.1".to_owned(),
            username:"guest".to_owned(),
            password:"guest".to_owned(),
            virtual_host:"fxoss".to_owned(),
            port: 5672 as u16,
            heartbeat: 60 as u32,
            queue_list: vec![],
        }
    }
}

#[derive(Debug, Clone, Serialize,Deserialize)]
pub struct ServerQueueConfig{
    pub queue: String,
    pub callback_url: Option<String>,
    pub callback_service: Option<String>,
}

impl Default for ServerQueueConfig {
    fn default() -> Self {
        ServerQueueConfig{ 
            queue: "test".to_owned(),
            callback_url: None,
            callback_service: None,
        }
    }
}



pub fn load_from_file(path:&String) ->  Result<AppConfig, Error> {
    let file = File::open(path)?;
    let reader = BufReader::new(file);

    // Read the JSON contents of the file as an instance of `User`.
    let config = serde_json::from_reader(reader);
    if config.is_err() {
        let e = config.err().unwrap();
        error!("parse config file {} error. message:{:?}",path, e);
        return Err(Error::new(std::io::ErrorKind::InvalidData, "parse config file"));
    }
    Ok(config.unwrap())
}